﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using IObjects;
using Entities;
using DataObjects.EFData;
using Utilities;

namespace DataObjects
{
    public class Account : IAccount
    {
        private AccountInfo _accountInfo;
        private string mode = string.Empty;
        private WebOnlineEntities datacontext;
        #region implement interface
        public AccountInfo AccountInfo
        {
            get
            {
                return _accountInfo;
            }
            set
            {
                _accountInfo = value;
            }
        }

        public string Mode
        {
            get
            {
                return mode;
            }
            set
            {
                mode = value;
            }
        }

        public int Save()
        {

            if (mode == Constants.MODE_INSERT)
            {
                return Insert();
            }

            throw new Exception("Mode is invalid in Account object");
        }

        public IList<AccountInfo> GetAccounts()
        {
            using (datacontext = new WebOnlineEntities())
            {
                var accountList = datacontext.TB_Account.Select(c => c.ToAccountInfo()).ToList();
                return accountList;
            }
        }
        public AccountInfo GetById(string id)
        {
            using (datacontext = new WebOnlineEntities())
            {
                var account = datacontext.TB_Account.Where(c => c.UserId == id).FirstOrDefault();
                if (account != null)
                {
                    return account.ToAccountInfo();
                }
                return null;
            }
        }

        public bool Login(string userId, string password, out string message)
        {
            message = string.Empty;
            using (datacontext = new WebOnlineEntities())
            {
                var account = datacontext.TB_Account.FirstOrDefault(a => a.UserId == userId);
                if (account == null)
                {
                    message = "Username do not exist in System. Please try another Username.";
                    return false;
                }
                else if (!account.IsActivated)
                {
                    message = "Account has not yet activated in System.";
                    return false;
                }
                else if (account.Password != password)
                {
                    message = "Wrong password. Please try again.";
                    account.FailedPasswordAttempCount++;
                    if (account.FailedPasswordAttempCount >= int.Parse(new Config().GetByName(Constants.LIMIT_PASSWORD_FAIL_LOGIN).Value))
                    {
                        Lock(account.UserId);
                    }
                    datacontext.SaveChanges();
                    return false;
                }
                else if (account.IsLockedOut)
                {
                    if (account.LastLockoutDate.Value.AddMinutes(double.Parse(new Config().GetByName(Constants.TIME_LOCKOUT_ACCOUNT).Value)) <= DateTime.Now)
                    {
                        account.IsLockedOut = false;
                        account.LastLockoutDate = DateTime.MinValue;
                        account.FailedPasswordAttempCount = 0;
                        account.LastLoginDate = DateTime.Now;
                        datacontext.SaveChanges();
                        return true;
                    }
                    else
                    {
                        message = "Account is locked out because login fail so many times. ";
                        return false;
                    }
                }
                else
                {
                    account.FailedPasswordAttempCount = 0;
                    account.LastLoginDate = DateTime.Now;
                    datacontext.SaveChanges();
                    return true;
                } 
            }
        }

        public bool ChangePassword(string userId, string newPass)
        {
            using (datacontext = new WebOnlineEntities())
            { 
                var account = datacontext.TB_Account.Where(c => c.UserId == _accountInfo.Id).FirstOrDefault();
                account.Password = newPass;
                account.LastPasswrodChangedDate = DateTime.Now;
                return datacontext.SaveChanges() > 0;
            }
        }

        public bool Lock(string userId)
        {
            using (datacontext = new WebOnlineEntities())
            {
                var account = datacontext.TB_Account.Where(c => c.UserId == _accountInfo.Id).FirstOrDefault();
                account.IsLockedOut = true;
                account.LastLockoutDate = DateTime.Now;
                return datacontext.SaveChanges() > 0;
            }
        }

        public bool UnLock(string userId)
        {
            using (datacontext = new WebOnlineEntities())
            {
                var account = datacontext.TB_Account.Where(c => c.UserId == _accountInfo.Id).FirstOrDefault();
                account.IsLockedOut = false;
                return datacontext.SaveChanges() > 0;
            }
        }

        public bool Activate(string userId)
        {
            using (datacontext = new WebOnlineEntities())
            {
                var account = datacontext.TB_Account.Where(c => c.UserId == _accountInfo.Id).FirstOrDefault();
                account.IsActivated = true;
                return datacontext.SaveChanges() > 0;
            }
        }

        public bool DeActivate(string userId)
        {
            using (datacontext = new WebOnlineEntities())
            {
                var account = datacontext.TB_Account.Where(c => c.UserId == _accountInfo.Id).FirstOrDefault();
                account.IsActivated = false;
                return datacontext.SaveChanges() > 0;
            }
        }
        public IList<AccountInfo> GetAccounts(SearchAccountInfo criteria, out int totalItems)
        {
            using (datacontext = new WebOnlineEntities())
            {
                List<AccountInfo> lstAccounts = null;
                totalItems = 0;
                // Query
                var result = datacontext.TB_Account.Include("TB_UserProfile").Where(a => String.IsNullOrEmpty(criteria.Keyword) ?
                                                                                        (String.IsNullOrEmpty(criteria.UserId) || a.UserId.ToLower().Contains(criteria.UserId.ToLower())) &&
                                                                                        (String.IsNullOrEmpty(criteria.CompanyName) || a.TB_UserProfile.CompanyName.ToLower().Contains(criteria.CompanyName.ToLower())) &&
                                                                                        (String.IsNullOrEmpty(criteria.Email) || a.TB_UserProfile.Email.ToLower().Contains(criteria.Email.ToLower())) &&
                                                                                        (String.IsNullOrEmpty(criteria.Fax) || a.TB_UserProfile.Fax.ToLower().Contains(criteria.Fax.ToLower())) &&
                                                                                        (String.IsNullOrEmpty(criteria.FullName) || a.TB_UserProfile.FullName.ToLower().Contains(criteria.FullName.ToLower())) &&
                                                                                        (String.IsNullOrEmpty(criteria.Phone)|| a.TB_UserProfile.Phone.ToLower().Contains(criteria.Phone.ToLower())) &&
                                                                                        (String.IsNullOrEmpty(criteria.Title)||a.TB_UserProfile.Title.ToLower().Contains(criteria.Title.ToLower())) 
                                                                                        : 
                                                                                        a.UserId.ToLower().Contains(criteria.Keyword.ToLower())||
                                                                                        a.TB_UserProfile.CompanyName.ToLower().Contains(criteria.Keyword.ToLower())||
                                                                                        a.TB_UserProfile.Email.ToLower().Contains(criteria.Keyword.ToLower())||
                                                                                        a.TB_UserProfile.Fax.ToLower().Contains(criteria.Keyword.ToLower())||
                                                                                        a.TB_UserProfile.FullName.ToLower().Contains(criteria.Keyword.ToLower())||
                                                                                        a.TB_UserProfile.Phone.ToLower().Contains(criteria.Keyword.ToLower())||
                                                                                        a.TB_UserProfile.Title.ToLower().Contains(criteria.Keyword.ToLower())
                                                                                        );
                if (criteria.IsActivated.HasValue)
                {
                    result = result.Where(a => a.IsActivated == criteria.IsActivated.Value);
                }
                if (criteria.IsLockedOut.HasValue)
                {
                    result = result.Where(a => a.IsLockedOut == criteria.IsLockedOut.Value);
                }
                if (criteria.Sex.HasValue)
                {
                    result = result.Where(a => a.TB_UserProfile.Sex == criteria.Sex.Value);
                }
                if (criteria.CreateDateFrom.HasValue)
                {
                    result = result.Where(a => a.CreateDate >= criteria.CreateDateFrom.Value);
                }
                if (criteria.CreateDateTo.HasValue)
                {
                    result = result.Where(a => a.CreateDate <= criteria.CreateDateTo.Value);
                }
                // Sort
                Func<TB_Account, string> orderingFunction = (t => criteria.SortColumn == "useridCol" ? t.UserId :
                                                                             criteria.SortColumn == "createdateCol" ? t.CreateDate.ToString() :
                                                                             criteria.SortColumn == "isactivateCol" ? t.IsActivated.ToString() :
                                                                             criteria.SortColumn == "islockoutCol" ? t.IsLockedOut.ToString() :
                                                                             criteria.SortColumn == "firstnameCol" ? t.TB_UserProfile.FirstName :
                                                                             criteria.SortColumn == "fullnameCol" ? t.TB_UserProfile.FullName :
                                                                             criteria.SortColumn == "emailCol" ? t.TB_UserProfile.Email:
                                                                             criteria.SortColumn == "companynameCol" ? t.TB_UserProfile.CompanyName:
                                                                             criteria.SortColumn == "titleCol" ? t.TB_UserProfile.Title :
                                                                             criteria.SortColumn == "taxidCol" ? t.TB_UserProfile.TaxId :
                                                                             criteria.SortColumn == "sexCol" ? t.TB_UserProfile.Sex.ToString() :
                                                                             criteria.SortColumn == "lastnameCol" ? t.TB_UserProfile.LastName : "");
                if (criteria.DirectionSort == "asc")
                {
                    result = result.OrderBy(orderingFunction).AsQueryable();
                }
                else
                {
                    result = result.OrderByDescending(orderingFunction).AsQueryable();
                }
                totalItems = result.Count();
                // Paging
                result = criteria.DisplayLength > 0 ? result.Skip(criteria.DisplayStart).Take(criteria.DisplayLength) : result;
                lstAccounts = new List<AccountInfo>();
                lstAccounts = result.Select(x => new AccountInfo()
                {
                    Id = x.UserId,
                    CreateDate = x.CreateDate,
                    FailedPasswordAttempCount = x.FailedPasswordAttempCount,
                    IsActivated = x.IsActivated,
                    IsLockedOut = x.IsLockedOut,
                    LastLockoutDate = x.LastLockoutDate,
                    LastLoginDate = x.LastLoginDate,
                    LastPasswodChangedDate = x.LastPasswrodChangedDate,

                    BillToAddress1 = x.TB_UserProfile.BillToAddress1,
                    BillToAddress2 = x.TB_UserProfile.BillToAddress2,
                    BillToCity = x.TB_UserProfile.BillToCity,
                    BillToContact = x.TB_UserProfile.BillToContact,
                    BillToCountry = x.TB_UserProfile.BillToCountry,
                    BillToZip = x.TB_UserProfile.BillToZip,
                    CompanyName = x.TB_UserProfile.CompanyName,
                    Description = x.TB_UserProfile.Description,
                    Email = x.TB_UserProfile.Email,
                    Fax = x.TB_UserProfile.Fax,
                    FirstName = x.TB_UserProfile.FirstName,
                    FullName = x.TB_UserProfile.FullName,
                    ImageAvatar = x.TB_UserProfile.ImageAvatar,
                    LastName = x.TB_UserProfile.LastName,
                    Phone = x.TB_UserProfile.Phone,
                    Sex = x.TB_UserProfile.Sex,
                    TaxId = x.TB_UserProfile.TaxId,
                    Title = x.TB_UserProfile.Title
                }).ToList();
                return lstAccounts;
            }
        }
        #endregion
        #region methods
        private int Insert()
        {
            using (datacontext = new WebOnlineEntities())
            {
                datacontext.AddToTB_Account(this._accountInfo.ToTB_Account());
                return datacontext.SaveChanges();
            }
        }
        #endregion


        
    }
}
